/*
 * This file is part of the MicroPython K210 project, https://github.com/loboris/MicroPython_K210_LoBo
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 LoBo (https://github.com/loboris)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/* Copyright 2018 Canaan Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _W25QXX_H
#define _W25QXX_H
#include <stdint.h>

// 83 MHz max speed results in SPI3 clocks:
// 82.333 MHz at PLL0 = 988 MHz (115 us for 4096 bytes read)
// 67.166 MHz at PLL0 = 806 MHz (142 us for 4096 bytes read)
#define WQ25QXX_MAX_SPEED                   40000000
// SPI3 clock for sending/reading commands
#define SPI_STAND_CLOCK_RATE                20000000

#define CHIP_SELECT                         1
#define WAIT_CYCLE                          8
// Setting the FRAME_LENGTH(_XXXX) to 32 causes every 32-bit value
// to have bytes SWAPPED (0x11223344 -> 0x44332211)
#define FRAME_LENGTH_SINGLE                 8
#define FRAME_LENGTH_DUAL                   32
#define FRAME_LENGTH_QUAD                   32

#define INSTRUCTION_LENGTH                  8
#define ADDRESS_LENGTH                      24

#define SPI_SLAVE_SELECT                    (0x01)

#define w25qxx_FLASH_PAGE_SIZE              256
#define w25qxx_FLASH_SECTOR_SIZE            4096
#define w25qxx_FLASH_PAGE_NUM_PER_SECTOR    16
#define w25qxx_FLASH_CHIP_SIZE              (16777216 UL)

#define WRITE_ENABLE                        0x06
#define WRITE_DISABLE                       0x04
#define READ_REG1                           0x05
#define READ_REG2                           0x35
#define READ_REG3                           0x15
#define WRITE_REG1                          0x01
#define WRITE_REG2                          0x31
#define WRITE_REG3                          0x11
#define READ_DATA                           0x03
#define FAST_READ                           0x0B
#define FAST_READ_DUAL_OUTPUT               0x3B
#define FAST_READ_QUAD_OUTPUT               0x6B
#define FAST_READ_DUAL_IO                   0xBB
#define FAST_READ_QUAD_IO                   0xEB
#define DUAL_READ_RESET                     0xFFFF
#define QUAD_READ_RESET                     0xFF
#define PAGE_PROGRAM                        0x02
#define QUAD_PAGE_PROGRAM                   0x32
#define SECTOR_ERASE                        0x20
#define BLOCK_32K_ERASE                     0x52
#define BLOCK_64K_ERASE                     0xD8
#define CHIP_ERASE                          0x60
#define READ_ID                             0x90
#define READ_JEDEC_ID                       0x9F
#define READ_UNIQUE                         0x4B
#define ENABLE_QPI                          0x38
#define EXIT_QPI                            0xFF
#define ENABLE_RESET                        0x66
#define RESET_DEVICE                        0x99

#define REG1_BUSY_MASK                      0x01
#define REG1_WEL_MASK                       0x02
#define REG2_QUAD_MASK                      0x02

#define LETOBE(x)     ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24))
/* clang-format on */

#define SPI_DEFAULT_CLOCK 25000000

/**
 * @brief      w25qxx operating status enumerate
 */
enum w25qxx_status_t
{
    W25QXX_OK = 0,
    W25QXX_BUSY,
    W25QXX_ERROR,
};

extern bool w25qxx_spi_check;
extern bool w25qxx_debug;
extern uint32_t w25qxx_max_speed;
extern uint32_t w25qxx_flash_speed;
extern uint32_t w25qxx_actual_speed;
extern uint8_t work_trans_mode;
extern uint8_t __attribute__((aligned(8))) swap_buf[w25qxx_FLASH_SECTOR_SIZE];
extern uint8_t *w25qxx_flash_ptr;
extern uint16_t *w25qxx_flash_ptr16;
extern uint32_t *w25qxx_flash_ptr32;
extern bool w25qxx_swap_dat;

void w25qxx_clear_counters();
void w25qxx_get_counters(uint32_t *r, uint32_t *w, uint32_t *e, uint64_t *time);

uint32_t w25qxx_init(uintptr_t spi_in, uint8_t mode, double clock_rate);
enum w25qxx_status_t w25qxx_write_data(uint32_t addr, uint8_t* data_buf, uint32_t length);
enum w25qxx_status_t w25qxx_read_data(uint32_t addr, uint8_t* data_buf, uint32_t length);
enum w25qxx_status_t w25qxx_sector_erase(uint32_t addr);
enum w25qxx_status_t w25qxx_read_id(uint8_t *manuf_id, uint8_t *device_id);
enum w25qxx_status_t w25qxx_read_jedec_id(uint8_t *jedec_id);
enum w25qxx_status_t w25qxx_read_unique(uint8_t *unique_id);
enum w25qxx_status_t w25qxx_enable_xip_mode(void);
enum w25qxx_status_t w25qxx_disable_xip_mode(void);

#endif

